package org.acghub.mtdb.common;

import org.acghub.mtdb.common.type.TypeDateTime;
import org.acghub.mtdb.common.type.impl.*;
import org.acghub.mtdb.util.StringUtil;
import org.w3c.dom.Element;

import java.util.ArrayList;
import java.util.List;

/**
 * @author zhouhe
 */
public class TypeFactory {

    public static void init() {
        new TypeBoolean();
        new TypeByte();
        new TypeShort();
        new TypeInt();
        new TypeLong();
        new TypeFloat();
        new TypeDouble();
        new TypeString();
        new TypeDateTime();
    }


    public static Type find(Naming parent, String type) {
        return StringUtil.isEmpty(type) ? null : parent.search(type.split("\\."), Type.class);
    }

    public static Type resolve(Naming parent, String type, String key, String value) {
        Type r = find(parent, type);
        if (r != null) {
            return r;
        }
        Type keyType;
        Type valueType = find(parent, value);
        if (valueType == null) {
            return null;
        }
        switch (type) {
            case "list" -> {
                return new TypeList(parent, valueType);
            }
            case "vector" -> {
                return new TypeVector(parent, valueType);
            }
            case "deque" -> {
                return new TypeDeque(parent, valueType);
            }
            case "set" -> {
                return new TypeSet(parent, valueType);
            }
            case "treeset" -> {
                return new TypeTreeSet(parent, valueType);
            }
            case "map" -> {
                if ((keyType = find(parent, key)) != null) {
                    return new TypeMap(parent, keyType, valueType);
                }
            }
            case "treemap" -> {
                if ((keyType = find(parent, key)) != null) {
                    return new TypeTreeMap(parent, keyType, valueType);
                }
            }
        }
        return null;
    }

    public static <T> T create(Class<T> clazz, Object... args) {
        try {
            if (args == null || args.length == 0) {
                return clazz.getDeclaredConstructor().newInstance();
            }
            List<Class<?>> classes = new ArrayList<>();
            for (Object arg : args) {
                if (arg instanceof Element) {
                    classes.add(Element.class);
                } else {
                    classes.add(arg.getClass());
                }
            }
            return clazz.getDeclaredConstructor(classes.toArray(new Class[0])).newInstance(args);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
